/***************************************************************************
 *   Copyright (C) 2011 by The rPem3d developers                           *
 *   elseifkk@users.sf.net                                                 *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
 ***************************************************************************/
#include "config.h"

#include <sys/shm.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/param.h>
#include <sys/sysctl.h>

key_t shmkey=0;
int shmid=0;
unsigned char *shmdata=0;
bool exist;

int pid2name ( int pid, char *pathname )
{
#if defined(__FreeBSD__) && (__FreeBSD__ >= 7)
	int error, name[4];
	size_t len=1024;
	name[0] = CTL_KERN;
	name[1] = KERN_PROC;
	name[2] = KERN_PROC_PATHNAME;
	name[3] = pid;
	error = sysctl ( name, 4, pathname, &len, NULL, 0 );
	if ( error < 0 || len<=1 )
	{
		perror ( "sysctl" );
		return 0;
	}
	return 1;
#else
	return 0; // error
#endif
}

int open_shm ( char *pathname, int uid, size_t s )
{
#if defined(__FreeBSD__) && (__FreeBSD__ >= 7)
	int flg;
	char str[128];

	if ( ( shmkey = ftok ( pathname, uid ) ) == -1 )
	{
		perror ( "ftok" );
		return 0;
	}

	/* Create the segment. */
	flg= 0666;
	if ( ( shmid = shmget ( shmkey, s, flg ) ) < 0 )
	{
		exist=false;
		flg= ( IPC_CREAT | 0666 );
		if ( ( shmid = shmget ( shmkey, s, flg ) ) < 0 )
		{
			perror ( "shmget" );
			return 0;
		}

	}
	else
	{
		exist=true;
	}

	sprintf ( str,"%d",shmkey );
	setenv ( "RP3SHMKEY",str,1 );
	sprintf ( str,"%d",shmid );
	setenv ( "RP3SHMID",str,1 );

	/* attach the segment to data space. */
	shmdata = ( unsigned char * ) shmat ( shmid, ( void * ) 0, 0 );
	if ( shmdata == ( unsigned char * )-1 )
	{
		perror ( "shmat" );
		return 0;
	}
	bzero ( shmdata,s );
	if ( exist ) return -shmid;
	return shmid;
#else
	return 0; // error
#endif
}

void* get_shm_addr ( size_t offset )
{
	return offset+shmdata;
}

int close_shm ( void )
{
#if defined(__FreeBSD__) && (__FreeBSD__ >= 7)
	if ( shmdata==0 ) return 0;
	if ( shmdt ( shmdata ) ==-1 )
	{
		perror ( "shmdt" );
		return 1;
	}
	else
	{
		/* Destroy the segment */
		if ( shmctl ( shmid, IPC_RMID, 0 ) == -1 )
		{
			perror ( "shmctl" );
			return 1;
		}
		return 0;
	}
#else
	return 1; // error
#endif
}

int put_shm ( int code, size_t offset )
{
	if ( shmdata==0 ) return 1;
	memcpy ( shmdata+offset,&code,sizeof ( int ) );
	return 0;
}

int get_shm ( int *code, size_t offset )
{
	if ( shmdata==0 ) return 1;
	memcpy ( code,shmdata+offset,sizeof ( int ) );
	return 0;
}
